#ifndef TWOREFCOUNTS_H__MINCOM__COMMONKIT__INCLUDED_
#define TWOREFCOUNTS_H__MINCOM__COMMONKIT__INCLUDED_

namespace MinCOM
{

	class TwoRefCountInfo 
		: public Loki::Private::TwoRefCountInfo
	{
	public:
		
		TwoRefCountInfo( bool strong );

		virtual ~TwoRefCountInfo();

		static TwoRefCountInfo* Create( bool strong );

		static void Release( TwoRefCountInfo* info );

	private:

		void DoRelease();

	};

	template 
	<
		class T
	>
	class TwoRefCounts
	{
	protected:

		explicit TwoRefCounts( bool strong )
			: m_counts( TwoRefCountInfo::Create(strong) )
			, m_p( NULL )
		{
		}

		TwoRefCounts( const T * p, bool strong )
			: m_counts( TwoRefCountInfo::Create(strong) )
			, m_p( const_cast<T*>(p) )
		{
		}

		TwoRefCounts( const TwoRefCounts & rhs, bool strong ) 
			: m_counts( rhs.m_counts )
			, m_p( rhs.m_p )
		{
			Increment( strong );
		}

		inline bool Release( bool strong )
		{
			return Decrement( strong );
		}

		void Increment( bool strong )
		{
			if ( strong )
			{
				m_counts->IncStrongCount();				
				if ( m_p ) m_p->AddRef();
			}
			else
			{
				m_counts->IncWeakCount();
			}
		}

		bool Decrement( bool strong )
		{
			if ( strong )
			{
				T * pointer = m_p;

				SetPointer(NULL);

				if ( pointer )
					pointer->Release();

				m_counts->DecStrongCount();		

				if ( m_counts->HasStrongPointer() )
				{
					SetPointer(pointer);
				}
			}
			else
			{
				m_counts->DecWeakCount();
			}

			return !m_counts->HasStrongPointer();
		}

		bool HasStrongPointer( void ) const
		{
			return m_counts->HasStrongPointer();
		}

		void Swap( TwoRefCounts & rhs )
		{
			std::swap( m_counts, rhs.m_counts );
			std::swap( m_p, rhs.m_p );
		}

		void SetPointer( T * p )
		{
			m_p = p;
		}

		void ZapPointer( void )
		{
			assert( !m_counts->HasStrongPointer() );
			if ( m_counts->HasWeakPointer() )
			{
				SetPointer(NULL);
			}
			else
			{
				TwoRefCountInfo::Release(m_counts);
				m_counts = NULL;
			}
		}

		inline T * & GetPointerRef( void ) const
		{
			if ( !m_counts )
				return NULL;

			return m_p;
		}

		bool Merge( TwoRefCounts& rhs )
		{
			while ( m_counts->HasStrongPointer() )
				m_counts->DecStrongCount();

			while ( m_counts->HasWeakPointer() )
				m_counts->DecWeakCount();

			TwoRefCountInfo::Release(m_counts);

			m_counts = rhs.m_counts;

			Increment( true );

			return true;
		}

	public:

		inline T * GetPointer( void ) const
		{
			if ( !m_counts )
				return NULL;

			return m_p; 
		}

	private:

		TwoRefCounts( void );
		TwoRefCounts & operator = ( const TwoRefCounts & );

	public:

		/// Pointer to all shared data.
		TwoRefCountInfo * m_counts;

	private:
		
		T * m_p;
	};

}

#endif // !TWOREFCOUNTS_H__MINCOM__COMMONKIT__INCLUDED_
